package com.example.myspringframework.beans.factory.support;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.example.myspringframework.beans.BeansException;
import com.example.myspringframework.beans.factory.DisposableBean;
import com.example.myspringframework.beans.factory.ObjectFactory;
import com.example.myspringframework.beans.factory.config.SingletonBeanRegistry;

/**
 * 默认单例bean注册表的实现
 * 实现了获取单例bean的方法，同时定义并实现了一个添加单例bean的方法
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    // 一级缓存
    private final Map<String, Object> singletonObjects = new HashMap<>();
    // 二级缓存
    protected final Map<String, Object> earlySingletonObjects = new HashMap<>();
    // 三级缓存
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>();
    // 存储需要执行销毁方法的bean
    private final Map<String, DisposableBean> disposableBeans = new HashMap<>();

    /**
     * 获取一个单例bean
     */
    @Override
    public Object getSingleton(String beanName) {
        Object bean = this.singletonObjects.get(beanName);
        // 一级缓存找不到就从二级缓存找
        if (bean == null) {
            bean = this.earlySingletonObjects.get(beanName);
            // 二级缓存找不到就从三级缓存找
            if (bean == null) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    bean = singletonFactory.getObject();
                    // 从三级缓存放进二级缓存
                    this.earlySingletonObjects.put(beanName, bean);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
        return bean;
    }

    /**
     * 把单例bean添加到容器中，当执行到这步时说明bean的创建工作都已完成
     */
    @Override
    public void addSingleton(String beanName, Object singletonObject) {
        this.singletonObjects.put(beanName, singletonObject);
        // bean真正创建好后就从二级和三级缓存中移除
        this.earlySingletonObjects.remove(beanName);
        this.singletonFactories.remove(beanName);
    }

    /**
     * 把bean加入到三级缓存中
     */
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        singletonFactories.put(beanName, singletonFactory);
    }

    /**
     * 注册有销毁方法的bean
     */
    public void registerDisposableBean(String beanName, DisposableBean bean) {
        this.disposableBeans.put(beanName, bean);
    }

    /**
     * 执行所有bean的销毁方法
     */
    public void destroySingletons() {
        ArrayList<String> beanNames = new ArrayList<>(disposableBeans.keySet());
        for (String beanName : beanNames) {
            DisposableBean disposableBean = disposableBeans.remove(beanName);
            try {
                disposableBean.destroy();
            } catch (Exception e) {
                throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
            }
        }
    }
}
